package cn.harry.component.security.filter;

import cn.harry.common.api.ResultCode;
import cn.harry.common.exception.ApiException;
import cn.harry.component.security.constant.SecurityConstants;
import cn.harry.component.security.model.SysUserDetails;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import jakarta.annotation.Nonnull;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

/**
 * JWT登录授权过滤器
 *
 * @author harry
 * @公众号 Harry技术
 */
@Slf4j
public class JwtValidationFilter extends OncePerRequestFilter {

    private final UserDetailsService userDetailsService;

    // 密钥
    private final byte[] secretKey;

    public JwtValidationFilter(UserDetailsService userDetailsService, String secretKey) {
        this.userDetailsService = userDetailsService;
        this.secretKey = secretKey.getBytes();
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, @Nonnull HttpServletResponse response, @Nonnull FilterChain chain) throws ServletException, IOException {
        // 获取请求token
        String token = request.getHeader(HttpHeaders.AUTHORIZATION);
        try {
            // 如果请求头中没有Authorization信息，或者Authorization以Bearer开头，则认为是匿名用户
            if (StrUtil.isBlank(token) || !token.startsWith(SecurityConstants.JWT_TOKEN_PREFIX)) {
                chain.doFilter(request, response);
                return;
            }

            // 去除 Bearer 前缀
            token = token.substring(SecurityConstants.JWT_TOKEN_PREFIX.length());
            // 解析 Token
            JWT jwt = JWTUtil.parseToken(token);

            // 检查 Token 是否有效(验签 + 是否过期)
            boolean isValidate = jwt.setKey(secretKey).validate(0);
            if (!isValidate) {
                log.error("JwtValidationFilter error: token is invalid");
                throw new ApiException(ResultCode.UNAUTHORIZED);
            }
            JSONObject payloads = jwt.getPayloads();
            String username = payloads.getStr(JWTPayload.SUBJECT);
            SysUserDetails userDetails = (SysUserDetails) this.userDetailsService.loadUserByUsername(username);

            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authentication);
        } catch (Exception e) {
            log.error("JwtValidationFilter error: {}", e.getMessage());
            SecurityContextHolder.clearContext();
            throw new ApiException(ResultCode.UNAUTHORIZED);
        }
        // Token有效或无Token时继续执行过滤链
        chain.doFilter(request, response);
    }
}
